<?php
/**
 * 文件上传
 * @author:shuan@leju.com
 * $Id:Uploader.php 14-9-12 下午2:07 kangshu'an $
 */
class Uploader{
    private $allow_max_size = 2000000;//上传文件大小,字节
    
    private $new_name = '';//新文件名，不带后缀
    private $new_name_rule = '';//新文件名规则，可以是函数名或者方法名
    private $allow_mime_type = array();//允许上传的文件类型mime_type
    private $allow_ext = '*';//允许上传的后缀类型
    private $save_path = '/';//上传路径
    private $fieldname = 'upfile';//表单字段名称
    
    private $file = array();
    public $file_name = '';//原始文件名
    private $file_type = '';//文件mime类型
    private $file_size = '';//文件大小，字节
    private $file_tmp_name = '';//临时文件名
    
    private $error = array();//上传的错误信息
    /**
     * 初始化参数
     */
    public function init($config=array()){
        //查找本类的所有属性，并赋值
        $reflect = new ReflectionClass($this);
		$props = $reflect->getProperties();
		foreach ($props as $prop) {
            $name = $prop->getName();
             isset($config[$name]) && ($this->$name = $config[$name]);
        }

        $this->file = $_FILES[$this->fieldname];
        $this->file_name = $this->file['name'];
        $this->file_type = $this->file['type'];
        $this->file_size = $this->file['size'];
        $this->file_type = $this->file['type'];
        $this->file_tmp_name = $this->file['tmp_name'];
    }
    /**
     * 各种验证
     */
    public function check(){
        if (!is_uploaded_file($this->file_tmp_name)) {
            $this->error[] = '未上传文件';
            return false;
        }
        //验证大小
        if ($this->allow_max_size < $this->file_size) {
            $this->error[] = '超出上传大小';
            return false;
        }
        //验证类型
        if ($this->allow_ext != '*') {
            if (!is_array($this->allow_ext)) {
                $this->allow_ext = explode(',', $this->allow_ext);
            }
            //没有识别出来什么类型时根据后缀判断
            if ($this->file_type == 'application/octet-stream') {
                $ext = $this->getext();
                if (!in_array($ext, $this->allow_ext)) {
                    $this->error[] = '文件类型不允许上传'.$ext;
                    return false;
                }
            } else {
                $mime = require dirname(__FILE__) . '/mimes.php';
            
                foreach ($this->allow_ext as $ext) {
                    if (isset($mime[$ext])) {
                        if (is_array($mime[$ext])) {
                            $this->allow_mime_type += $mime[$ext];
                        } else {
                            $this->allow_mime_type[] = $mime[$ext];
                        }
                    }
                    if (!in_array($this->file_type, $this->allow_mime_type)) {
                        $this->error[] = '文件类型不允许上传mime';
                        return false;
                    }
                }
            }
        }
        return true;
    }
    /**
     * 得到上传路径
     */
    public function getpath(){
        if ($this->save_path == ''){
            $this->error[] = '请设置上传路径';
            return false;
        }
        if (function_exists('realpath') AND @realpath($this->save_path) !== false){
            $this->save_path = str_replace("\\", "/", realpath($this->save_path));
        }
        if ( !is_dir($this->save_path)){
            @mkdir($this->save_path, 0777, true);
        }
        if (!is_writable($this->save_path)){
            $this->error[] = '上传路径不可写';
            return false;
        }
        $this->save_path = preg_replace("/(.+?)\/*$/", "\\1/",  $this->save_path);
        return $this->save_path; 
    }
    /**
     * 得到文件名，包括后缀
     */
    public function getname(){
        //自定义文件名
        if (!empty($this->new_name)) {
            return $this->new_name.'.'.$this->getext();
        }
        //如果有函数或者方法
        if (!empty($this->new_name_rule)) {
            if (function_exists($this->new_name_rule)) {
                $name = $this->new_name_rule();
                return $name . $this->getext();
            }
            if (method_exists($this, $this->new_name_rule)) {
                $fun = $this->new_name_rule;
                $name = $this->$name();
                return $name . $this->getext();
            }
        }
        return $this->file_name;
    }
    /**
     * 原文件后缀
     */
    public function getext(){
        $ext = explode('.', $this->file_name);
        return end($ext);
    }
    /**
     * 得到错误信息
     */
    public function geterror(){
        return join(',', $this->error);
    }

    /**
     * 表单执行上传
     */
    public function up(){
        if ( !$this->file_tmp_name){
            switch($this->file['error']){
                case 1:	// UPLOAD_ERR_INI_SIZE
                    $this->error[] = '上传文件超出服务器设置大小';
                    return false;
                    break;
                case 2: // UPLOAD_ERR_FORM_SIZE
                    $this->error[] = '上传文件超出表单设置大小';
                    return false;
                    break;
                case 3: // UPLOAD_ERR_PARTIAL
                    $this->error[] = '部分上传失败';
                    return false;
                    break;
                case 4: // UPLOAD_ERR_NO_FILE
                    $this->error[] = '未选择上传文件';
                    return false;
                    break;
                case 6: // UPLOAD_ERR_NO_TMP_DIR
                    $this->error[] = '未找到临时目录';
                    return false;
                    break;
                case 7: // UPLOAD_ERR_CANT_WRITE
                    $this->error[] = '无法写入上传文件';
                    return false;
                    break;
            }
        }
        
        $filepath = $this->getpath().$this->getname();
        if (!empty($this->error)) {
            return false;
        }
        if (!@copy($this->file_tmp_name, $filepath)){
            if (!@move_uploaded_file($this->file_tmp_name, $filepath)){
                $this->error[] = 'upload_destination_error';
                return false;
            }
        }
        return $filepath;
    }
    /**
     * 流式上传
     */
    public function upstream(){
        
    }
}